/*
 * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
 *
 * https://www.mall4j.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */
package com.yami.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.dto.CategoryShopDTO;
import com.yami.shop.bean.enums.ProdStatusEnums;
import com.yami.shop.bean.enums.SigningStatus;
import com.yami.shop.bean.event.SigningCategoryInvalidEvent;
import com.yami.shop.bean.model.Category;
import com.yami.shop.bean.model.CategoryShop;
import com.yami.shop.bean.vo.CategoryShopVO;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.constants.CacheNames;
import com.yami.shop.common.constants.ProductCacheNames;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.i18n.LanguageEnum;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.dao.CategoryMapper;
import com.yami.shop.dao.CategoryShopMapper;
import com.yami.shop.dao.ProductMapper;
import com.yami.shop.service.CategoryShopService;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author lth
 * @Date 2021/7/28 10:26
 */
@Service
@AllArgsConstructor
public class CategoryShopServiceImpl extends ServiceImpl<CategoryShopMapper, CategoryShop> implements CategoryShopService {

    private final CategoryShopMapper categoryShopMapper;
    private final ProductMapper productMapper;
    private final CategoryMapper categoryMapper;
    private final ApplicationEventPublisher applicationEventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void signingCategory(List<CategoryShop> categoryShopList, Long shopId, Boolean isPlatform) {
        if (categoryShopList.size() > Constant.SIGNING_CATEGORY_LIMIT_NUM) {
            throw new YamiShopBindException("签约的分类信息不能超过" + Constant.SIGNING_CATEGORY_LIMIT_NUM);
        }
        // 处理分类扣率问题
        this.dealWithSigningCategoryInfo(categoryShopList, shopId, isPlatform, true);
        // 删除已签约的平台分类信息
        categoryShopMapper.delete(Wrappers.lambdaQuery(CategoryShop.class).eq(CategoryShop::getShopId, shopId));
        // 重新插入
        if (CollUtil.isNotEmpty(categoryShopList)) {
            categoryShopMapper.saveBatch(categoryShopList, shopId, isPlatform ? SigningStatus.SUCCESS.value() : SigningStatus.PENDING_REVIEW.value());
        }
        // 更新缓存
        this.removeCacheByShopIds(Collections.singletonList(shopId));
    }

    @Override
    public void insertBatchByShopId(List<CategoryShop> categoryShopList, Long shopId, Integer status) {
        if (CollUtil.isEmpty(categoryShopList)) {
            return;
        }
        int signedCount = categoryShopMapper.selectCount(Wrappers.lambdaQuery(CategoryShop.class).eq(CategoryShop::getShopId, shopId));
        if (signedCount + categoryShopList.size() > Constant.SIGNING_CATEGORY_LIMIT_NUM) {
            throw new YamiShopBindException("签约的分类信息不能超过" + Constant.SIGNING_CATEGORY_LIMIT_NUM);
        }
        categoryShopMapper.saveBatch(categoryShopList, shopId, status);
        removeCacheByShopIds(Collections.singletonList(shopId));
    }

    @Override
    @Cacheable(cacheNames = ProductCacheNames.LIST_SIGNING_CATEGORY_BY_SHOP_ID, key = "#shopId + ':' + #lang")
    public List<CategoryShopVO> listSigningCategoryByShopId(Long shopId, Integer lang) {
        return categoryShopMapper.listSigningCategoryByShopId(shopId, lang);
    }

    @Override
    @Cacheable(cacheNames = ProductCacheNames.LIST_AVAILABLE_SIGNING_CATEGORY_BY_SHOP_ID, key = "#shopId + ':' + #lang")
    public List<Category> listAvailableSigningCategory(Long shopId, Integer lang) {
        List<Category> threeCategoryList = categoryShopMapper.listSigningCategoryByShopIdAndStatus(shopId, 1, lang);
        if (CollUtil.isEmpty(threeCategoryList)) {
            // 签约分类为空时
            return new ArrayList<>();
        }
        List<Category> twoCategoryList = categoryMapper.getListByCategoryIds(threeCategoryList.stream().map(Category::getParentId).collect(Collectors.toSet()), I18nMessage.getLang());
        List<Category> oneCategoryList = categoryMapper.getListByCategoryIds(twoCategoryList.stream().map(Category::getParentId).collect(Collectors.toSet()), I18nMessage.getLang());
        threeCategoryList.addAll(twoCategoryList);
        threeCategoryList.addAll(oneCategoryList);
        return threeCategoryList;
    }

    @Override
    public List<Category> listRateByShopId(Long shopId) {
        return categoryShopMapper.listRateByShopId(shopId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByCategoryId(Long categoryId) {
        List<Long> shopIdList = categoryShopMapper.listShopIdByCategoryIds(Collections.singletonList(categoryId));
        // 删除与该分类id关联的信息
        categoryShopMapper.delete(Wrappers.lambdaQuery(CategoryShop.class).eq(CategoryShop::getCategoryId, categoryId));
        // 清除缓存
        removeCacheByShopIds(shopIdList);
    }

    @Override
    public void removeCacheByChangeCategoryIds(List<Long> categoryIds) {
        if (CollUtil.isEmpty(categoryIds)) {
            return;
        }
        List<Long> shopIdList = categoryShopMapper.listShopIdByCategoryIds(categoryIds);
        this.removeCacheByShopIds(shopIdList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeStatusByShopIdAndStatus(Long shopId, Integer oldStatus, Integer newStatus) {
        categoryShopMapper.changeStatusByShopIdAndStatus(shopId, oldStatus, newStatus);
        removeCacheByShopIds(Collections.singletonList(shopId));
    }

    /**
     *
     * @param categoryShopDTOList
     * @param shopId
     * @param isPlatform
     * @param isApplyShop
     */
    private void dealWithSigningCategoryInfo(List<CategoryShop> categoryShopDTOList, Long shopId, Boolean isPlatform, Boolean isApplyShop) {
        // 查找以前签约的分类信息列表
        List<CategoryShop> oldCategoryShopList = categoryShopMapper.selectList(Wrappers.lambdaQuery(CategoryShop.class).eq(CategoryShop::getShopId, shopId).orderByAsc(CategoryShop::getCategoryId));
        if (!isPlatform) {
            for (CategoryShop categoryShop : categoryShopDTOList) {
                // 查找是否存在
                int index = this.getIndex(categoryShop.getCategoryId(), oldCategoryShopList);
                if (index == -1) {
                    categoryShop.setRate(null);
                } else {
                    categoryShop.setCategoryShopId(oldCategoryShopList.get(index).getCategoryShopId());
                    categoryShop.setRate(oldCategoryShopList.get(index).getRate());
                    oldCategoryShopList.remove(index);
                }
            }
        } else {
            for (CategoryShop categoryShop : categoryShopDTOList) {
                // 查找是否存在
                int index = this.getIndex(categoryShop.getCategoryId(), oldCategoryShopList);
                if (index != -1) {
                    categoryShop.setCategoryShopId(oldCategoryShopList.get(index).getCategoryShopId());
                    oldCategoryShopList.remove(index);
                }
            }
        }
        if (!isApplyShop) {
            // 如果是开店时调用则不用执行下面方法
            return;
        }
        this.dealWithDeleteCategoryList(oldCategoryShopList, shopId);
    }

    /**
     * 根据分类id查找该分类在列表中的索引
     * @param categoryId 分类id
     * @param categoryShopList categoryId正序的列表
     * @return
     */
    private int getIndex(Long categoryId, List<CategoryShop> categoryShopList) {
        if (Objects.isNull(categoryId) || CollUtil.isEmpty(categoryShopList)) {
            return -1;
        }
        int leftIndex = 0;
        int rightIndex = categoryShopList.size() - 1;
        int midIndex;
        while (leftIndex <= rightIndex) {
            midIndex = leftIndex + ((rightIndex - leftIndex) >>> 1);
            Long currentId = categoryShopList.get(midIndex).getCategoryId();
            if (Objects.equals(categoryId, currentId)) {
                return midIndex;
            }
            if (currentId > categoryId) {
                rightIndex = midIndex - 1;
            } else {
                leftIndex = midIndex + 1;
            }
        }
        return -1;
    }

    /**
     * 处理签约失效的分类
     * @param categoryShopList
     * @param shopId
     */
    private void dealWithDeleteCategoryList(List<CategoryShop> categoryShopList, Long shopId) {
        List<Long> ids = categoryShopList.stream().map(CategoryShop::getCategoryId).collect(Collectors.toList());
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        productMapper.offlineProdByCategoryIdAndShopId(ids, ProdStatusEnums.SHOP_OFFLINE.getValue(), shopId);
    }

    @Override
    public void removeCacheByShopIds(List<Long> shopIds) {
        if (CollUtil.isEmpty(shopIds)) {
            return;
        }
        List<String> keyList = new ArrayList<>();
        shopIds.forEach(shopId -> {
            keyList.add(ProductCacheNames.LIST_AVAILABLE_SIGNING_CATEGORY_BY_SHOP_ID + CacheNames.UNION + shopId + CacheNames.UNION_KEY + LanguageEnum.LANGUAGE_ZH_CN.getLang());
            keyList.add(ProductCacheNames.LIST_AVAILABLE_SIGNING_CATEGORY_BY_SHOP_ID + CacheNames.UNION + shopId + CacheNames.UNION_KEY + LanguageEnum.LANGUAGE_EN.getLang());
            keyList.add(ProductCacheNames.LIST_SIGNING_CATEGORY_BY_SHOP_ID + CacheNames.UNION + shopId + CacheNames.UNION_KEY + LanguageEnum.LANGUAGE_ZH_CN.getLang());
            keyList.add(ProductCacheNames.LIST_SIGNING_CATEGORY_BY_SHOP_ID + CacheNames.UNION + shopId + CacheNames.UNION_KEY + LanguageEnum.LANGUAGE_EN.getLang());
        });
        RedisUtil.deleteBatch(keyList);
    }

    @Override
    public IPage<CategoryShopVO> pageSigningInfo(PageParam<CategoryShopVO> page, CategoryShopDTO categoryShop) {
        IPage<CategoryShopVO> categoryShopPage = categoryShopMapper.pageSigningInfo(page, categoryShop, I18nMessage.getLang());
        return categoryShopPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long shopId, Long categoryId) {
        int count = categoryShopMapper.delete(Wrappers.lambdaQuery(CategoryShop.class).eq(CategoryShop::getShopId, shopId).eq(CategoryShop::getCategoryId, categoryId));
        if (count != 1) {
            throw new YamiShopBindException("删除失败");
        }
        // 清除签约分类的缓存
        this.removeCacheByShopIds(Collections.singletonList(shopId));
        // 发送签约分类失效事件
        applicationEventPublisher.publishEvent(new SigningCategoryInvalidEvent(categoryId, shopId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRate(Long shopId, Long categoryId, Double rate) {
         boolean update = this.update(Wrappers.lambdaUpdate(CategoryShop.class)
                .set(CategoryShop::getRate, rate)
                .eq(CategoryShop::getShopId, shopId)
                .eq(CategoryShop::getCategoryId, categoryId));
         if (!update) {
             throw new YamiShopBindException("更新失败");
         }
         this.removeCacheByShopIds(Collections.singletonList(shopId));
    }
}
